package com.geek.factory.service.scheduler;

import com.geek.factory.entity.StockCheck;
import com.geek.factory.entity.Warehouse;
import com.geek.factory.service.IStockCheckDetailService;
import com.geek.factory.service.IStockCheckService;
import com.geek.factory.service.IWarehouseService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 库存盘点定时任务调度器
 */
@Component
@Slf4j
public class StockCheckScheduler {

    @Autowired
    private IStockCheckService stockCheckService;

    @Autowired
    private IStockCheckDetailService stockCheckDetailService;

    @Autowired
    private IWarehouseService warehouseService;

    @Value("${stock-check.scheduler.enabled:true}")
    private boolean schedulerEnabled;

    @Value("${stock-check.scheduler.monthly-enabled:true}")
    private boolean monthlyEnabled;

    @Value("${stock-check.scheduler.weekly-enabled:true}")
    private boolean weeklyEnabled;

    /**
     * 生成盘点单号
     * @param checkType 盘点类型（M=月度，W=周度）
     * @param warehouseId 仓库ID
     * @return 盘点单号
     */
    private String generateCheckNumber(String checkType, Integer warehouseId) {
        String prefix = "PD";  // PD = Physical Check
        LocalDateTime now = LocalDateTime.now();
        String dateStr = now.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String timeStr = now.format(DateTimeFormatter.ofPattern("HHmmss"));
        // 在盘点单号中加入仓库ID，确保唯一性
        return String.format("%s%s%s%03d%s", prefix, dateStr, timeStr, warehouseId, checkType);
    }

    /**
     * 每月1日凌晨2点执行月度库存盘点
     * cron表达式：秒 分 时 日 月 星期
     *
     * 测试用表达式说明：0 /2 * * * ?
            * 表示每2分钟执行一次
     *
             * 正式环境表达式说明：0 0 2 1 * ?
            * 表示每月1日凌晨2点执行
     */
    //@Scheduled(cron = "0 */2 * * * ?")  // 测试用：每2分钟执行一次
    @Scheduled(cron = "0 0 2 1 * ?") // 正式环境：每月1日凌晨2点
    public void scheduleMonthlyStockCheck() {
        if (!schedulerEnabled || !monthlyEnabled) {
            log.info("月度库存盘点定时任务已禁用，跳过执行");
            return;
        }

        log.info("开始执行月度库存盘点定时任务...");
        try {
            // 获取所有仓库
            List<Warehouse> warehouses = warehouseService.list();

            // 为每个仓库异步创建盘点单
            for (Warehouse warehouse : warehouses) {
                processMonthlyWarehouseStockCheck(warehouse);
            }

            log.info("月度库存盘点定时任务触发完成，共 {} 个仓库的盘点任务已提交到异步线程执行", warehouses.size());
        } catch (Exception e) {
            log.error("执行月度库存盘点定时任务时发生异常", e);
        }
    }

    /**
     * 异步处理单个仓库的月度盘点
     */
    @Async
    @Transactional
    public CompletableFuture<Boolean> processMonthlyWarehouseStockCheck(Warehouse warehouse) {
        log.info("开始异步处理仓库 {} 的月度盘点", warehouse.getWarehouseName());
        try {
            LocalDateTime now = LocalDateTime.now();
            
                // 创建盘点单
                StockCheck stockCheck = new StockCheck();
                stockCheck.setCheckName("系统自动月度盘点-" + warehouse.getWarehouseName() + "-" + now.getMonthValue() + "月");
                stockCheck.setCheckNo(generateCheckNumber("M", warehouse.getWarehouseId())); // 传入仓库ID
                stockCheck.setCheckType("full");
                stockCheck.setStatus("draft");
                stockCheck.setCreatedBy("system");
                stockCheck.setCreatedTime(now);
                stockCheck.setStartTime(now);
                stockCheck.setEndTime(now.plusDays(3)); // 设置3天后结束
                stockCheck.setCheckDate(LocalDate.now());
                stockCheck.setWarehouseId(warehouse.getWarehouseId()); // 设置仓库ID
                stockCheck.setWarehouseName(warehouse.getWarehouseName()); // 设置仓库名称
                stockCheck.setResponsiblePerson(warehouse.getManager()); // 设置负责人为仓库管理员

                // 保存盘点单
                boolean saved = stockCheckService.save(stockCheck);
                if (saved) {
                    log.info("月度盘点单创建成功，仓库：{}，ID: {}, 单号: {}",
                            warehouse.getWarehouseName(), stockCheck.getCheckId(), stockCheck.getCheckNo());

                    // 生成所有类型的盘点明细（包括产品和原料）
                    generateStockCheckDetails(stockCheck.getCheckId(), warehouse.getWarehouseId(), "all");
                return CompletableFuture.completedFuture(true);
                } else {
                    log.error("月度盘点单创建失败，仓库：{}", warehouse.getWarehouseName());
                return CompletableFuture.completedFuture(false);
            }
        } catch (Exception e) {
            log.error("处理仓库 {} 的月度盘点时发生异常", warehouse.getWarehouseName(), e);
            return CompletableFuture.completedFuture(false);
        }
    }

    /**
     * 每周日凌晨3点执行周度库存盘点
     *
     * 测试用表达式说明：30 /2 * * * ?
            * 表示每2分钟的30秒执行一次
     *
             * 正式环境表达式说明：0 0 3 ? * SUN
     * 表示每周日凌晨3点执行
     */
    //@Scheduled(cron = "30 */2 * * * ?")  // 测试用：每2分钟的30秒执行一次
    @Scheduled(cron = "0 0 3 ? * SUN") // 正式环境：每周日凌晨3点
    public void scheduleWeeklyStockCheck() {
        if (!schedulerEnabled || !weeklyEnabled) {
            log.info("周度库存盘点定时任务已禁用，跳过执行");
            return;
        }

        log.info("开始执行周度库存盘点定时任务...");
        try {
            // 获取所有仓库
            List<Warehouse> warehouses = warehouseService.list();

            // 为每个仓库异步创建盘点单
            for (Warehouse warehouse : warehouses) {
                processWeeklyWarehouseStockCheck(warehouse);
            }

            log.info("周度库存盘点定时任务触发完成，共 {} 个仓库的盘点任务已提交到异步线程执行", warehouses.size());
        } catch (Exception e) {
            log.error("执行周度库存盘点定时任务时发生异常", e);
        }
    }

    /**
     * 异步处理单个仓库的周度盘点
     */
    @Async
    @Transactional
    public CompletableFuture<Boolean> processWeeklyWarehouseStockCheck(Warehouse warehouse) {
        log.info("开始异步处理仓库 {} 的周度盘点", warehouse.getWarehouseName());
        try {
            LocalDateTime now = LocalDateTime.now();
            
                // 创建盘点单
                StockCheck stockCheck = new StockCheck();
                stockCheck.setCheckName("系统自动周度盘点-" + warehouse.getWarehouseName() + "-第" + (now.getDayOfYear() / 7 + 1) + "周");
                stockCheck.setCheckNo(generateCheckNumber("W", warehouse.getWarehouseId())); // 传入仓库ID
                stockCheck.setCheckType("cycle");
                stockCheck.setStatus("draft");
                stockCheck.setCreatedBy("system");
                stockCheck.setCreatedTime(now);
                stockCheck.setStartTime(now);
                stockCheck.setEndTime(now.plusDays(1)); // 设置1天后结束
                stockCheck.setCheckDate(LocalDate.now());
                stockCheck.setWarehouseId(warehouse.getWarehouseId()); // 设置仓库ID
                stockCheck.setWarehouseName(warehouse.getWarehouseName()); // 设置仓库名称
                stockCheck.setResponsiblePerson(warehouse.getManager()); // 设置负责人为仓库管理员

                // 保存盘点单
                boolean saved = stockCheckService.save(stockCheck);
                if (saved) {
                    log.info("周度盘点单创建成功，仓库：{}，ID: {}, 单号: {}",
                            warehouse.getWarehouseName(), stockCheck.getCheckId(), stockCheck.getCheckNo());

                    // 生成所有类型的盘点明细（包括产品和原料）
                    generateStockCheckDetails(stockCheck.getCheckId(), warehouse.getWarehouseId(), "all");
                return CompletableFuture.completedFuture(true);
                } else {
                    log.error("周度盘点单创建失败，仓库：{}", warehouse.getWarehouseName());
                return CompletableFuture.completedFuture(false);
            }
        } catch (Exception e) {
            log.error("处理仓库 {} 的周度盘点时发生异常", warehouse.getWarehouseName(), e);
            return CompletableFuture.completedFuture(false);
        }
    }

    /**
     * 生成库存盘点明细
     *
     * @param checkId 盘点单ID
     * @param warehouseId 仓库ID
     * @param itemType 物品类型
     */
    @Async
    private void generateStockCheckDetails(Integer checkId, Integer warehouseId, String itemType) {
        try {
            log.info("异步为盘点单 {} 生成 {} 类型的盘点明细，仓库ID: {}", checkId, itemType, warehouseId);
            boolean success = stockCheckDetailService.generateDetailsFromInventory(checkId, warehouseId, itemType);
            if (success) {
                log.info("成功为盘点单 {} 生成 {} 类型的盘点明细", checkId, itemType);
            } else {
                log.warn("为盘点单 {} 生成 {} 类型的盘点明细失败", checkId, itemType);
            }
        } catch (Exception e) {
            log.error("生成盘点明细时发生异常: 盘点单={}, 仓库={}, 类型={}", checkId, warehouseId, itemType, e);
            // 继续处理其他仓库，不中断整个任务
        }
    }

    /**
     * 测试方法 - 手动触发盘点
     * 此方法仅用于测试，可以手动触发盘点任务
     */
    public void testStockCheck(String type) {
        log.info("手动触发{}盘点任务...", type);
        if ("monthly".equals(type)) {
            scheduleMonthlyStockCheck();
        } else if ("weekly".equals(type)) {
            scheduleWeeklyStockCheck();
        } else {
            log.error("无效的盘点类型: {}", type);
        }
    }
}